package ph.com.gs3.formalistics.presenter;

import java.util.List;

import ph.com.gs3.formalistics.R;
import ph.com.gs3.formalistics.global.utilities.logging.FLLogger;
import ph.com.gs3.formalistics.model.valueobjects.business.Comment;
import ph.com.gs3.formalistics.model.valueobjects.business.User;
import ph.com.gs3.formalistics.presenter.fragments.views.CommentsViewFragment;
import ph.com.gs3.formalistics.presenter.fragments.views.CommentsViewFragment.CommentListViewActionListener;
import ph.com.gs3.formalistics.presenter.fragments.workers.CommentsWorkerFragment;
import ph.com.gs3.formalistics.presenter.fragments.workers.CommentsWorkerFragment.CommentDeleteFailedException;
import ph.com.gs3.formalistics.service.managers.SessionManager;
import ph.com.gs3.formalistics.service.managers.SessionManager.Mode;
import ph.com.gs3.formalistics.service.services.DeleteCommentsMarkedForDeletionService;
import ph.com.gs3.formalistics.service.services.OutgoingCommentsSubmitService;
import ph.com.gs3.formalistics.view.valueobjects.parsers.DateUtilities;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Toast;

public class CommentsActivity extends Activity implements CommentListViewActionListener {

	public static final String TAG = CommentsActivity.class.getSimpleName();
	public static final String EXTRA_CURRENT_USER = "current_user";
	public static final String EXTRA_CURRENT_DOCUMENT_FORM_WEB_ID = "document_form_web_id";
	public static final String EXTRA_CURRENT_DOCUMENT_WEB_ID = "document_web_id";

	private CommentsWorkerFragment commentsWorkerFragment;
	private CommentsViewFragment commentsViewFragment;

	private List<Comment> commentsOnDisplay;

	private User currentUser;
	private String currentDocumentFormWebId;
	private String currentDocumentWebId;

	// shortcut fields
	private String currentUserWebId;
	private String currentServer;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_comments);
		getActionBar().setIcon(R.drawable.commentstrokelight);

		initializeWorkerFragment();
		initializeData();
		registerBroadcastReceivers();

		if (savedInstanceState == null) {
			commentsViewFragment = CommentsViewFragment.createInstance(this, commentsOnDisplay);
			getFragmentManager().beginTransaction().add(R.id.container, commentsViewFragment)
			        .commit();

		}

	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		int id = item.getItemId();
		if (id == R.id.action_delete_comment) {
			AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item
			        .getMenuInfo();

			deleteComment(commentsOnDisplay.get(info.position));

			return true;
		}

		return super.onContextItemSelected(item);
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, view, menuInfo);

		AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
		int position = info.position;

		Comment selectedComment = commentsOnDisplay.get(position);

		// if the author of this comment is the same as the current user
		if (currentUserWebId.equals(selectedComment.getAuthorWebId())
		        && currentServer.equals(selectedComment.getServer())) {
			getMenuInflater().inflate(R.menu.comment_list_item, menu);
		} else {
			getMenuInflater().inflate(R.menu.comment_list_item_no_delete, menu);

		}

	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		unregisterBroadcastReceivers();
	}

	private void initializeWorkerFragment() {

		FragmentManager fragmentManager = getFragmentManager();
		commentsWorkerFragment = (CommentsWorkerFragment) fragmentManager
		        .findFragmentByTag(CommentsWorkerFragment.TAG);

		if (commentsWorkerFragment == null) {
			commentsWorkerFragment = CommentsWorkerFragment.createInstance(getApplicationContext());
			fragmentManager.beginTransaction()
			        .add(commentsWorkerFragment, CommentsWorkerFragment.TAG).commit();
		}

	}

	private void initializeData() {

		Intent intent = getIntent();
		Bundle extras = intent.getExtras();

		currentUser = (User) extras.getSerializable(EXTRA_CURRENT_USER);

		currentUserWebId = Integer.toString(currentUser.getWebId());
		currentServer = currentUser.getAccountServer();

		currentDocumentFormWebId = extras.getString(EXTRA_CURRENT_DOCUMENT_FORM_WEB_ID);
		currentDocumentWebId = extras.getString(EXTRA_CURRENT_DOCUMENT_WEB_ID);

		commentsOnDisplay = commentsWorkerFragment.getDocumentComments(currentServer,
		        currentDocumentFormWebId, currentDocumentWebId);
	}

	private void registerBroadcastReceivers() {

		// @formatter:off
		IntentFilter submitCommentBroadcastReceiverFilter = new IntentFilter();
		
		submitCommentBroadcastReceiverFilter.addAction(OutgoingCommentsSubmitService.ACTION_ON_COMMENT_SUBMITTED);
		submitCommentBroadcastReceiverFilter.addAction(OutgoingCommentsSubmitService.ACTION_ON_SUBMIT_FAILED);
		submitCommentBroadcastReceiverFilter.addCategory(Intent.CATEGORY_DEFAULT);

		registerReceiver(submitCommentBroadcastReceiver, submitCommentBroadcastReceiverFilter);

		IntentFilter deleteCommentBroadcastReceiverFilter = new IntentFilter();
		
		deleteCommentBroadcastReceiverFilter.addAction(DeleteCommentsMarkedForDeletionService.ACTION_ON_SERVICE_STARTED);
		deleteCommentBroadcastReceiverFilter.addAction(DeleteCommentsMarkedForDeletionService.ACTION_ON_SERVICE_DONE);
		deleteCommentBroadcastReceiverFilter.addCategory(Intent.CATEGORY_DEFAULT);
		
		registerReceiver(deleteCommentBroadcastReceiver, deleteCommentBroadcastReceiverFilter);
		// @formatter:on

	}

	private void unregisterBroadcastReceivers() {

		unregisterReceiver(submitCommentBroadcastReceiver);
		unregisterReceiver(deleteCommentBroadcastReceiver);

	}

	private void deleteComment(Comment comment) {

		// validate if the comment is the user's own comment
		if (!isCommentOwnedByCurrentUser(comment)) {
			Toast.makeText(this, "You cannot delete this comment", Toast.LENGTH_LONG).show();
			return;
		}

		// validate if the comment is still being processed
		if (comment.isCurrentlyBeingProcessed()) {
			Toast.makeText(this, "This comment is still being processed, try again later.",
			        Toast.LENGTH_LONG).show();
			return;
		}

		if (comment.isOutgoing() && !comment.isCurrentlyBeingProcessed()) {
			// delete the comment in the database

			try {
				commentsWorkerFragment.deleteComment(comment.getDbId());
			} catch (CommentDeleteFailedException e) {
				Toast.makeText(CommentsActivity.this,
				        "Failed to delete comment: " + e.getMessage(), Toast.LENGTH_LONG).show();
			}

		} else if (!comment.isOutgoing()) {
			// mark the comment for deletion then run the service for deleting comments
			try {
				commentsWorkerFragment.markCommentForDeletion(comment.getDbId());
				if (SessionManager.getApplicationInstance().getMode() == Mode.ONLINE) {
					startDeleteCommentsService();
				}
			} catch (CommentDeleteFailedException e) {
				Toast.makeText(CommentsActivity.this,
				        "Failed to delete comment: " + e.getMessage(), Toast.LENGTH_LONG).show();
			}

		}

		// update the UI
		commentsViewFragment.removeComment(comment);

	}

	private boolean isCommentOwnedByCurrentUser(Comment comment) {

		String userWebId = Integer.toString(currentUser.getWebId());
		return userWebId.equals(comment.getAuthorWebId());

	}

	// ==========================================================================================
	// {{ View Implementation Methods

	@Override
	public void onSubmitCommentCommand(String commentText) {

		Comment comment = new Comment();

		// author details
		comment.setAuthorWebId(Integer.toString(currentUser.getWebId()));
		comment.setAuthorDisplayName(currentUser.getDisplayName());
		comment.setAuthorImageURL(currentUser.getImageURL());
		comment.setServer(currentUser.getAccountServer());

		// comment details
		comment.setText(commentText);

		comment.setDocumentFormWebId(currentDocumentFormWebId);
		comment.setDocumentWebId(currentDocumentWebId);

		comment.setCurrentlyBeingProcessed(true);

		// give the comment a stub id using the current date and time
		comment.setPendingStubId(DateUtilities.getServerFormattedCurrentDate());

		// submit the comment

		Comment updatedComment = startSubmitCommentService(comment);

		// update the UI
		commentsViewFragment.addComment(updatedComment);

	}

	// }}

	private Comment startSubmitCommentService(Comment commentToSubmit) {

		// save comment as outgoing comment
		Comment updatedComment = commentsWorkerFragment
		        .saveCommentAsOutgoingComment(commentToSubmit);

		Intent outgoingCommentsSubmitServiceIntent = new Intent(CommentsActivity.this,
		        OutgoingCommentsSubmitService.class);

		outgoingCommentsSubmitServiceIntent.putExtra(
		        OutgoingCommentsSubmitService.EXTRA_CURRENT_USER, currentUser);

		startService(outgoingCommentsSubmitServiceIntent);

		return updatedComment;

	}

	private void startDeleteCommentsService() {

		Intent deleteCommentsService = new Intent(CommentsActivity.this,
		        DeleteCommentsMarkedForDeletionService.class);
		deleteCommentsService.putExtra(OutgoingCommentsSubmitService.EXTRA_CURRENT_USER,
		        currentUser);
		startService(deleteCommentsService);

	}

	private BroadcastReceiver submitCommentBroadcastReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {

			String action = intent.getAction();
			Bundle extras = intent.getExtras();

			if (action.equals(OutgoingCommentsSubmitService.ACTION_ON_COMMENT_SUBMITTED)) {

				Comment comment = (Comment) extras
				        .getSerializable(OutgoingCommentsSubmitService.EXTRA_SUBMITTED_COMMENT);

				if (currentDocumentFormWebId.equals(comment.getDocumentFormWebId())
				        && currentDocumentWebId.equals(comment.getDocumentWebId())) {
					commentsViewFragment.markCommentAsProcessed(comment.getDbId());
				}

			}

			if (action.equals(OutgoingCommentsSubmitService.ACTION_ON_SUBMIT_FAILED)) {
				FLLogger.e(TAG, "No handle for submit comment failure");
				Toast.makeText(CommentsActivity.this, "Failed to submit comment", Toast.LENGTH_LONG)
				        .show();
			}

		}

	};

	private BroadcastReceiver deleteCommentBroadcastReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();

			FLLogger.d(TAG, action);

		}

	};

}
